package lupita.controller;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.NIOFSDirectory;
import org.apache.lucene.util.Version;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;


/**
 * Servlet implementation class IndexerServlet
 */
public class IndexerServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

	
	
	public static final String INDEX_DIR ="/FILES_INDEX";
	
	public static final String REPOSITORY_DIR ="/FILES_REPOSITORY";
	
	private IndexWriter writer;	
	
  	private boolean DEBUG = true;                     

  	static Set<String> textualMetadataFields           
  		= new HashSet<String>();                     
  
  	static {                                           
  		textualMetadataFields.add(Metadata.TITLE);       
  		textualMetadataFields.add(Metadata.AUTHOR);      
		textualMetadataFields.add(Metadata.COMMENTS);    
		textualMetadataFields.add(Metadata.KEYWORDS);    
		textualMetadataFields.add(Metadata.DESCRIPTION); 
		textualMetadataFields.add(Metadata.SUBJECT);
		textualMetadataFields.add(Metadata.FORMAT);
  	}	
       
    /**
     * constructor por defecto
     */
    public IndexerServlet() {
    	
    }	

	/**
	 * 
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		HttpSession session = request.getSession();
		
		PrintWriter out = response.getWriter();
		
		ServletContext servletContext = session.getServletContext();
		String indexDir = servletContext.getRealPath(IndexerServlet.INDEX_DIR);
		String repositoryDir = servletContext.getRealPath(IndexerServlet.REPOSITORY_DIR);		
		
		TikaConfig config = TikaConfig.getDefaultConfig();  
	    List<String> parsers = new ArrayList<String>(config.getParsers().keySet());  
	    
	    Collections.sort(parsers);                         
	    
	    Iterator<String> it = parsers.iterator();          
	    
	    System.out.println("Mime type parsers:");          
	    
	    //Remover
	    while(it.hasNext()) {                              
	      System.out.println("  " + it.next());            
	    }                                                  
	    
	    System.out.println();	    
	    
	    try {
	    
	    	long start = new Date().getTime();
	    	this.setUpIndexer(indexDir);
		    int numIndexed = this.index(repositoryDir, null);
		    this.close();
		    long end = new Date().getTime();
		    
		    long milliseconds = (end-start);
            double seconds = milliseconds/1024;
            int decimalPlace = 2;
            BigDecimal bd = new BigDecimal(seconds);
            bd = bd.setScale(decimalPlace, BigDecimal.ROUND_UP);
            seconds = bd.doubleValue();

            request.setAttribute("isIndizado", true);
            
           // out.println("<script type='text/javascript'>alert('Indexando " + numIndexed + " archivos en "
		     // + seconds + " segundos ');history.go(-1)</script>");		
            
            
            request.setAttribute("numIndexed", numIndexed);
            request.setAttribute("seconds", seconds);
	    	
	    }catch(Exception e) {
	    	e.printStackTrace();
	    }
	    
	    RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher("/searcher.jsp");
		requestDispatcher.forward(request, response);
	}
	
	private void setUpIndexer(String indexDir) throws Exception {	
		
		Directory dir = NIOFSDirectory.open(new File(indexDir));
	    
	    StandardAnalyzer standardAnalyzer = new StandardAnalyzer(Version.LUCENE_30);
		
	    writer = new IndexWriter(dir,
	                 standardAnalyzer,
	                 true, IndexWriter.MaxFieldLength.UNLIMITED);
	}


	  public void close() throws IOException {
		  writer.optimize();
		  writer.close();
	  }

	  public int index(String dataDir, FileFilter filter)
	    throws Exception {

	    File[] files = new File(dataDir).listFiles();

	    for (File f: files) {
	      if (!f.isDirectory() && !f.isHidden() && f.exists() && f.canRead() &&  (filter == null || filter.accept(f))) {
	        indexFile(f);
	      }
	    }

	    return writer.numDocs();                     
	  }


	  private void indexFile(File f) throws Exception {
	    //Remover
	    System.out.println("Indexing " + f.getCanonicalPath());
	    Document doc = getDocument(f);
	    writer.addDocument(doc);                              
	  }
	  
	  
	  private Document getDocument(File f) throws Exception {

		    Metadata metadata = new Metadata();
		    metadata.set(Metadata.RESOURCE_NAME_KEY, f.getName());   

		    InputStream is = new FileInputStream(f);      
		    Parser parser = new AutoDetectParser();       
		    
		    ContentHandler handler = new BodyContentHandler(); 
		    
		    ParseContext context = new ParseContext();   
		    context.set(Parser.class, parser);           

		    try {
		      parser.parse(is, handler, metadata,      
		                   new ParseContext());        
		    } finally {
		      is.close();
		    }

		    Document doc = new Document();

		    doc.add(new Field("contents", handler.toString(),           
		                      Field.Store.NO, Field.Index.ANALYZED));   
		    
		    //Remover
		    if (DEBUG) {
		      System.out.println("  todo el texto: " + handler.toString());
		    }
		    
		    for(String name : metadata.names()) {         
		      String value = metadata.get(name);
		      
		      if (textualMetadataFields.contains(name)) {
		        doc.add(new Field("contents", value,      
		                          Field.Store.YES, Field.Index.ANALYZED));
		      }
		      		      

		      doc.add(new Field(name, value, Field.Store.YES, Field.Index.ANALYZED));

		      if (DEBUG) {
		        System.out.println("  " + name + ": " + value);
		      }
		    }

		    if (DEBUG) {
		      System.out.println();
		    }

		    // nombre del archivo
		    doc.add(new Field("filename", f.getName(),     
		             Field.Store.YES, Field.Index.NOT_ANALYZED));
		    
		    doc.add(new Field("title", f.getName(),     
		             Field.Store.YES, Field.Index.NOT_ANALYZED));
		    
		    doc.add(new Field("contents", f.getName(),      
                    Field.Store.YES, Field.Index.ANALYZED));
		    
		    // ruta completa del archivo
		    doc.add(new Field("fullpath", f.getCanonicalPath(),
					Field.Store.YES, Field.Index.NOT_ANALYZED));
		    
		    // tamanio del archivo en bytes
		    long fileLength = f.length();						
		    
			double fLengthKb = fileLength/1024;        
	        int decimalPlace = 2;
	        BigDecimal bd = new BigDecimal(fLengthKb);
	        bd = bd.setScale(decimalPlace, BigDecimal.ROUND_UP);
	        fLengthKb = bd.doubleValue();
	        	        	        
	        String fLength= Double.toString(fileLength);
	        
	        
		    doc.add(new Field("filelength", fLength,
					Field.Store.YES, Field.Index.NOT_ANALYZED));
		    		    
		    String strFileLen = Double.toString(fLengthKb)+ "kb";
		    
		    
		    doc.add(new Field("contents",strFileLen ,      
                    Field.Store.YES, Field.Index.ANALYZED));

		    return doc;
	  }

}
